package Derivation;


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;

import Basics.*;

public class DeriveByProgramBottomUp extends DeriveByProgram 
{
	Map<String, Vector<Atom>> addedInstAtomsInLastIteration = new HashMap<String, Vector<Atom>>();
	
	
	public DeriveByProgramBottomUp (Rule ... irs)
	{
		super(irs);
	}
	
	
	
	public DeriveByProgramBottomUp (Program p)
	{
		super(p);
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: DeriveFromProgramIterationBottomUp																				
	/** Description: Finds all Derivations for the rule according to db 				
	/*************************************************************************************************************/
	
	public void DeriveFromProgramIterationBottomUp ()
	{
		for (Rule rule : this.p.getRules()) 
		{
			if (false == IsBodyEDB(rule) || true == this.addedInstAtomsInLastIteration.isEmpty()) //good enough condition???
			{
				DeriveByRuleBottomUp ruleDeriver = new DeriveByRuleBottomUp(rule);
				ruleDeriver.FindDerivationsForRuleBottomUp();
				this.derivationsVec.add(ruleDeriver.getDerivations());
				this.GetAddedInstAtoms();
			}
		}
	}
	
	
	/*************************************************************************************************************/
	/** Title: IsBodyEDB																				
	/** Description: Check if rule can derive a fact only with DB atoms  				
	/*************************************************************************************************************/
	
	public boolean IsBodyEDB (Rule rule)
	{
		boolean retVal = true;
		for (Atom bodyAtom : rule.getBody()) 
		{
			if (false == bodyAtom.IsAtomRelationEdb(this.p)) 
			{
				retVal = false;
			}
		}
		
		return retVal;
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: GetAddedInstAtoms																				
	/** Description:  				
	/*************************************************************************************************************/
	
	public void GetAddedInstAtoms ()
	{
		for (Vector<Rule> vector : this.derivationsVec) 
		{
			for (Rule rule : vector) 
			{
				if (false == this.addedInstAtomsInLastIteration.containsKey(rule.getHead().getName())) 
				{
					this.addedInstAtomsInLastIteration.put(rule.getHead().getName(), new Vector<Atom>());
				}
				
				this.addedInstAtomsInLastIteration.get(rule.getHead().getName()).add(rule.getHead());
			}
		}
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: InstantiateAllRelevantsInRule																				
	/** Description: 				
	/*************************************************************************************************************/
	
	public List<Rule> InstantiateAllRelevantsInRule (Rule rule)
	{
		List<Rule> instRuleVector = new CopyOnWriteArrayList<Rule>();
		for (Atom bodyAtom : rule.getBody()) 
		{
			if (this.addedInstAtomsInLastIteration.containsKey(bodyAtom.getName())) 
			{
				for (Atom instAtom : this.addedInstAtomsInLastIteration.get(bodyAtom.getName())) 
				{
					Rule temp = new Rule (rule);
					temp.SwapToInstAtomAndPartiallyInst(bodyAtom, instAtom);					
					if (false == instRuleVector.contains(temp))
					{
						instRuleVector.add(temp);
					}
				}
			}
		}
		
		return instRuleVector;
	}
}
